/**
 * CfgMngr is the Configuration Manager of the CSS responsible for distributing the dynamic configurations
 * of subsystem and keeping the registration of all services
 */
package za.org.jcicada.cfgmngr.impl;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import za.org.jcicada.cfgmngr.IConfigurationServer;
import za.org.jcicada.cfgmngr.SystemSetType;
import za.org.jcicada.confss.impl.ConfSS;
import za.org.jcicada.genss.ServiceURN;
import za.org.jcicada.genss.SystemURN;
import za.org.jcicada.genss.messages.Result;
import za.org.jcicada.genss.sensor.SensorURN;
import za.org.jcicada.genss.sensor.impl.Sensor;

/**
 * The Configuration Manager Subsystem offers functionality to automatically
 * load its subsystem ID from a properties file, and creates configuration and
 * services interfaces during construction. The id and interfaces are available
 * via getters.
 */
public class CfgMngr extends ConfSS {

    /** class logger */
    private static final Log logger = LogFactory.getLog(CfgMngr.class);

    /** The subsystem ID property name */
    public static final String SYSTEM_NAME = "CfgMngr";

    /** Handle to configuration server object */
    private ConfigurationServer configServer;
    
    /** The name of the subsystem properties file */
    public static final String STATIC_PROPERTIES_FILE = "CfgMngr.static.properties";
    
    /** The name of the physical properties file */
    public static final String PHYSICAL_PROPERTIES_FILE = "CfgMngr.physical.properties";

    /** The name of the system types properties file */
    public static final String TYPE_PROPERTIES_FILE = "CfgMngr.type.properties";

    /** static configuration */
    public CfgMngrStatic cfgMngrStatic = new CfgMngrStatic();
    
    /** dynamic configuration */
    public CfgMngrDynamicConfiguration cfgMngrDynamic = new CfgMngrDynamicConfiguration();

    /** URN for the configuration server interface. */
    private ServiceURN configurationURN;
    
    /** URN for the system subject interface. */
    private ServiceURN systemsURN;
    
    /** URN for the physical server interface. */
    private ServiceURN physicalURN;

    /**
     * Default constructor loads properties.
     */
    public CfgMngr() throws URISyntaxException {
        this(PropertyLoader.loadProperties(PHYSICAL_PROPERTIES_FILE),
        		PropertyLoader.loadProperties(TYPE_PROPERTIES_FILE),
        		PropertyLoader.loadProperties(STATIC_PROPERTIES_FILE));
    }
    
    /**
     * Construct configuration manager with specified properties.
     * 
     * @param physicalProperties the physical mapping from system to physical location
     * @param typeClassMap the mapping from system type to class
     * @param staticProperties the static configuration properties
     * @throws URISyntaxException
     */
    public CfgMngr(Properties physicalProperties, Properties typeClassMap, Properties staticProperties) throws URISyntaxException {
    	super(new SystemURN(SYSTEM_NAME), null);
        configurationURN = new ServiceURN(getSystemURN(), "configuration");
        systemsURN = new ServiceURN(getSystemURN(), SystemSubject.URN_SERVICE);
        physicalURN = new ServiceURN(getSystemURN(), PhysicalServer.URN_SERVICE);
    	this.configServer = new ConfigurationServer(new PhysicalServer(physicalProperties), typeClassMap);
    	cfgMngrStatic.loadProperties(staticProperties);
    }

    public IConfigurationServer getConfigurationServer() {
        return configServer;
    }

    @Override
    public void duringInitialize() throws Exception {
        // setup the acceptors which registers the services
        internalSetupAcceptors(cfgMngrStatic.configurationUrls, new ConfigurationAcceptListener(getConfigurationServer()), configurationURN);
        internalSetupAcceptors(cfgMngrStatic.systemsUrls, new SystemsAcceptListener(getConfigurationServer().getSystemSubject()), systemsURN);
        internalSetupAcceptors(cfgMngrStatic.physicalUrls, new PhysicalAcceptListener(getConfigurationServer().getPhysicalServer()), physicalURN);
        // tell ConfSS what the location of Configuration Services is
        setCfgMngrLocationURI(getServiceLocationURI("tcp", configurationURN));
        // continue to ConfSS initialization
        super.duringInitialize();
    }
    
    @Override
    public void duringShutdown() throws Exception {
	    super.duringShutdown();
    	configServer.stop();
    }

    @Override
	public void replyGetConfiguration(Result result, Object configuration) {
		super.replyGetConfiguration(result, configuration);
		cfgMngrDynamic.loadProperties((Properties) configuration);
		configServer.initialize(cfgMngrDynamic);
		configServer.setFullSystemURNs(cfgMngrDynamic.getEnabledSystemURNs());
	}

	public void replyLocateService(Result result, ServiceURN serviceURN, URI locationURI) {
    }

    public void replySystemSet(Result result, SystemSetType type, Set<SystemURN> systemURNs) {
    }
    
    public void replyFullSystemSet(Result result, Set<SystemURN> systemURNs) {
    }

    public void replySensorSet(Result result, SystemURN systemURN, Set<SensorURN> sensorURNs) {
    }
    
    

    @Override
	protected void addSensors() throws URISyntaxException {
		super.addSensors();
        for (Sensor sensor : configServer.getSensors()) {
            addSensor(getSystemURN(), sensor);
        }
	}

	/**
     * Main function takes no arguments. A cfgmngr knows what it subsystemURI
     * will be since there can be only one!
     * 
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        try {
            boolean restart = true;
            while (restart) {
                CfgMngr cfgmngr = new CfgMngr();
                cfgmngr.initialize();
                restart = cfgmngr.waitHalt();
                cfgmngr.shutdown();
            }
        } catch (URISyntaxException ex) {
            logger.fatal("Unable to start CfgMngr with invalid URI", ex);
        }
    }

}
